package net.lab1024.smartadmin.common.reload;

import net.lab1024.smartadmin.common.reload.interfaces.SmartReloadCommandInterface;
import net.lab1024.smartadmin.common.reload.interfaces.SmartReloadThreadLogger;
import org.jetbrains.annotations.NotNull;

import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Reload 调度器
 *
 * @author zhuoda
 */
public class SmartReloadScheduler {

    /*
        ScheduledThreadPoolExecutor类继承了ThreadPoolExecutor并实现了ScheduledExecutorService接口。
        主要用于在给定的延迟后执行任务或者定期执行任务。
        作用类似于java.util包下的Timer类，
        但是比Timer功能更强大、更灵活，因为Timer只能控制单个线程延迟或定期执行，而ScheduledThreadPoolExecutor对应的是多个线程的后台线程。
     */
    private ScheduledThreadPoolExecutor executor;

    private SmartReloadThreadLogger logger;

    SmartReloadScheduler(SmartReloadThreadLogger logger, int threadCount) {
        // 构造一个ScheduledThreadPoolExecutor对象
        this.executor = new ScheduledThreadPoolExecutor(threadCount, new SmartReloadSchedulerThreadFactory());
        this.logger = logger;
    }

    void shutdown() {
        try {
            executor.shutdown();
        } catch (Throwable e) {
            logger.error("<<SmartReloadScheduler>> shutdown ", e);
        }
    }

    /**
     * 创建并执行一个在给定初始延迟后首次启用的定期操作，
     *  随后，在每一次执行终止和下一次执行开始之间都存在给定的延迟。
     *  如果任务的任一执行遇到异常，就会取消后续执行。
     *  否则，只能通过执行程序的取消或终止方法来终止该任务
     *
     * @param command
     * @param initialDelay
     * @param delay
     * @param unit
     */
    void addCommand(SmartReloadCommandInterface command, long initialDelay, long delay, TimeUnit unit) {
        // 创建并执行一个在给定初始延迟后首次启用的定期操作，随后，在每一次执行终止和下一次执行开始之间都存在给定的延迟。
        //  如果任务的任一执行遇到异常，就会取消后续执行。否则，只能通过执行程序的取消或终止方法来终止该任务。
        /*
            command - 要执行的任务
            initialdelay - 首次执行的延迟时间
            delay - 一次执行终止和下一次执行开始之间的延迟
            unit - initialdelay 和 delay 参数的时间单位
         */
        executor.scheduleWithFixedDelay(new ScheduleRunnable(command, this.logger), initialDelay, delay, unit);
    }

    static class ScheduleRunnable implements Runnable {

        private SmartReloadCommandInterface command;

        private SmartReloadThreadLogger logger;

        public ScheduleRunnable(SmartReloadCommandInterface command, SmartReloadThreadLogger logger) {
            this.command = command;
            this.logger = logger;
        }

        @Override
        public void run() {
            try {
                command.doTask();
            } catch (Throwable e) {
                logger.error("", e);
            }
        }
    }

    /*
        介绍
            简单来说就是用来创建线程的，其中也只是有一个newthread方法

        一些常用的作用
            1、给线程命名，查看创建线程数
            2、给线程设置是否是后台运行
            3、设置线程优先级
     */
    static class SmartReloadSchedulerThreadFactory implements ThreadFactory {

        private static final AtomicInteger POOL_NUMBER = new AtomicInteger(1);

        private final ThreadGroup group;

        private final AtomicInteger threadNumber = new AtomicInteger(1);

        private final String namePrefix;

        SmartReloadSchedulerThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
            namePrefix = "smartreload-" + POOL_NUMBER.getAndIncrement() + "-thread-";
        }

        @Override
        public Thread newThread(@NotNull Runnable r) {
            Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);

            if (t.isDaemon()) {
                t.setDaemon(false);
            }
            if (t.getPriority() != Thread.NORM_PRIORITY) {
                t.setPriority(Thread.NORM_PRIORITY);
            }

            return t;
        }
    }

}
